home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / domain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-20  |  11.3 KB  |  458 lines

  1. /*
  2.  * Copyright (c) 1986 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #include "sendmail.h"
  22.  
  23. #ifndef lint
  24. # ifdef NAMED_BIND
  25. static char sccsid[] = "@(#)domain.c    5.22 (Berkeley) 6/1/90 (with name server)";
  26. static char  rcsid[] = "@(#)$Id: domain.c,v 5.22.0.16 1991/06/21 12:46:31 paul Exp $ (with name server)";
  27. # else /* !NAMED_BIND */
  28. static char sccsid[] = "@(#)domain.c    5.22 (Berkeley) 6/1/90 (without name server)";
  29. static char  rcsid[] = "@(#)$Id: domain.c,v 5.22.0.16 1991/06/21 12:46:31 paul Exp $ (without name server)";
  30. # endif /* NAMED_BIND */
  31. #endif /* not lint */
  32.  
  33. #ifdef NAMED_BIND
  34.  
  35. # include <sys/param.h>
  36. # include <errno.h>
  37. # ifdef ISC
  38. #  include <net/errno.h>
  39. # endif /* ISC */
  40. # include <arpa/nameser.h>
  41. # include <resolv.h>
  42. # include <netdb.h>
  43.  
  44. # ifdef __STDC__
  45. #  ifdef CC_WONT_PROMOTE
  46. static int HostInClass(const char *, const char);
  47. #  else    /* !CC_WONT_PROMOTE */
  48. static int HostInClass(const char *, const int);
  49. #  endif /* CC_WONT_PROMOTE */
  50. # else /* !__STDC__ */
  51. static int HostInClass();
  52. # endif /* __STDC__ */
  53.  
  54. typedef union
  55. {
  56.     HEADER qb1;
  57.     char qb2[PACKETSZ];
  58. } querybuf;
  59.  
  60. extern int h_errno;
  61. static char hostbuf[MAXMXHOSTS*PACKETSZ];
  62.  
  63. /*
  64. **  GETMXRR -- Get MX Resource Records for a host name.
  65. **
  66. **    Ask the DNS for MX records about the given host.  Sort the
  67. **    list by preference value and truncate it if the local host
  68. **    is in the list.
  69. **
  70. **    Parameters:
  71. **        host -- the host name to look up
  72. **        mxhosts -- pointer to list of MX hosts for name
  73. **        rcode -- used to pass back type of DNS error
  74. **
  75. **    Returns:
  76. **        Number of MX hosts found or -1 on error (non-existent
  77. **        host, server failure, etc)
  78. **
  79. **    Side Effects:
  80. **        None.
  81. */
  82.  
  83. getmxrr(host, mxhosts, rcode)
  84.     const char *host;
  85.     char **mxhosts;
  86.     int *rcode;
  87. {
  88.     register u_char *eom, *cp;
  89.     register int i, j, n, nmx;
  90.     register char *bp;
  91.     HEADER *hp;
  92.     querybuf answer;
  93.     int ancount, qdcount, buflen, seenlocal;
  94.     u_short pref, localpref, type, prefer[MAXMXHOSTS];
  95.  
  96.     errno = 0;
  97.     n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer));
  98.     if (n < 0)
  99.     {
  100.         if (tTd(8, 1))
  101.             printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n",
  102.                 errno, h_errno);
  103.         switch (h_errno)
  104.         {
  105. # ifndef NO_DATA
  106. #  define NO_DATA    NO_ADDRESS
  107. # endif /* NO_DATA */
  108.           case NO_DATA:
  109.           case NO_RECOVERY:
  110.             /* no MX data on this host */
  111.             goto punt;
  112.  
  113.           case HOST_NOT_FOUND:
  114.             /* the host just doesn't exist */
  115.             *rcode = EX_NOHOST;
  116.             break;
  117.  
  118.           case TRY_AGAIN:
  119.             /* couldn't connect to the name server */
  120.             if (!UseNameServer && errno == ECONNREFUSED)
  121.                 goto punt;
  122.  
  123.             /* it might come up later; better queue it up */
  124.             *rcode = EX_TEMPFAIL;
  125.             break;
  126.         }
  127.  
  128.         /* irreconcilable differences */
  129.         return (-1);
  130.     }
  131.  
  132.     /* find first satisfactory answer */
  133.     hp = (HEADER *)&answer;
  134.     cp = (u_char *)&answer + sizeof(HEADER);
  135.     eom = (u_char *)&answer + n;
  136.     for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  137.         if ((n = dn_skipname(cp, eom)) < 0)
  138.             goto punt;
  139.     nmx = 0;
  140.     seenlocal = 0;
  141.     buflen = sizeof(hostbuf);
  142.     bp = hostbuf;
  143.     ancount = ntohs(hp->ancount);
  144.     while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS)
  145.     {
  146.         if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
  147.             break;
  148.         cp += n;
  149.         GETSHORT(type, cp);
  150.          cp += sizeof(u_short) + sizeof(u_long);
  151.         GETSHORT(n, cp);
  152.         if (type != T_MX)
  153.         {
  154.             if (tTd(8, 1) || _res.options & RES_DEBUG)
  155.                 printf("unexpected answer type %d, size %d\n",
  156.                     type, n);
  157.             cp += n;
  158.             continue;
  159.         }
  160.         GETSHORT(pref, cp);
  161.         if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
  162.             break;
  163.         cp += n;
  164.         if (HostInClass(bp, 'w') || HostInClass(bp, 'j'))
  165.         {
  166.             if (seenlocal == 0 || pref < localpref)
  167.                 localpref = pref;
  168.             seenlocal = 1;
  169.             continue;
  170.         }
  171.         prefer[nmx] = pref;
  172.         mxhosts[nmx++] = bp;
  173.         n = strlen(bp) + 1;
  174.         bp += n;
  175.         buflen -= n;
  176.     }
  177.     if (nmx == 0)
  178.     {
  179. punt:        mxhosts[0] = strcpy(hostbuf, host);
  180.         return(1);
  181.     }
  182.  
  183.     /* sort the records */
  184.     for (i = 0; i < nmx; i++)
  185.     {
  186.         for (j = i + 1; j < nmx; j++)
  187.         {
  188.             if (prefer[i] > prefer[j] ||
  189.                 (prefer[i] == prefer[j] && (rand()/3 & 1) == 0))
  190.             {
  191.                 register int temp;
  192.                 register char *temp1;
  193.  
  194.                 temp = prefer[i];
  195.                 prefer[i] = prefer[j];
  196.                 prefer[j] = temp;
  197.                 temp1 = mxhosts[i];
  198.                 mxhosts[i] = mxhosts[j];
  199.                 mxhosts[j] = temp1;
  200.             }
  201.         }
  202.         if (seenlocal && prefer[i] >= localpref)
  203.         {
  204.             /*
  205.              * truncate higher pref part of list; if we're
  206.              * the best choice left, we should have realized
  207.              * awhile ago that this was a local delivery.
  208.              */
  209.             if (i == 0)
  210.                 goto punt;
  211.             nmx = i;
  212.             break;
  213.         }
  214.     }
  215.     return(nmx);
  216. }
  217. /*
  218. **  HOSTINCLASS -- Test whether a hostname is part of a class.
  219. **
  220. **    Parameters:
  221. **        h -- name to check
  222. **        class -- class id letter
  223. **
  224. **    Returns:
  225. **        TRUE -- h found to be a member of class
  226. **        FALSE -- not a member
  227. **
  228. **    Side Effects:
  229. **        none
  230. */
  231.  
  232. static int
  233. HostInClass(h, class)
  234.     const char *h, class;
  235. {
  236.     STAB *s = stab(h, ST_CLASS, ST_FIND);
  237.     return (s != NULL && bitnset(class, s->s_class));
  238. }
  239. /*
  240. **  GETCANONNAME -- Get the canonical name of the given host.
  241. **
  242. **    Query the DNS to find the canonical name of the named host.
  243. **    The MX records are checked at the same time.  If the best host
  244. **    is localhost, then some other transport method must be used to
  245. **    deliver the message.  Returning FALSE causes sendmail to fall
  246. **    through to alternate routing, usually pathalias.
  247. **
  248. **    Parameters:
  249. **        host -- the name to canonicalize
  250. **        hbsize -- size of host string
  251. **
  252. **    Returns:
  253. **        TRUE -- Canonical name found and best MX record not localhost
  254. **        FALSE -- Best MX record points to localhost or DNS error
  255. **
  256. **    Side Effects:
  257. **        The host argument is re-written with the canonical name.
  258. */
  259.  
  260. bool
  261. getcanonname(host, hbsize)
  262.     char *host;
  263.     int hbsize;
  264. {
  265.     extern int h_errno;
  266.     register u_char *eom, *cp;
  267.     register int n; 
  268.     HEADER *hp;
  269.     querybuf answer;
  270.     u_short type;
  271.     int first, ancount, qdcount, loopcnt;
  272.     char nbuf[PACKETSZ];
  273.     u_short MailPreference = (u_short) -1;
  274.     char MailAgent[MAXNAME];
  275.     char MyName[MAXNAME];
  276.     char **MyAliases;
  277.  
  278.     MailAgent[0] = '\0';
  279.  
  280.     loopcnt = 0;
  281. loop:
  282.     /*
  283.      * Use query type of ANY if possible (NO_WILDCARD_MX), which will
  284.      * find types CNAME, A, and MX, and will cause all existing records
  285.      * to be cached by our local server.  If there is (might be) a
  286.      * wildcard MX record in the local domain or its parents that are
  287.      * searched, we can't use ANY; it would cause fully-qualified names
  288.      * to match as names in a local domain.
  289.      *
  290.      * This is at most a micro-performance tweak that can have serious
  291.      * side effects.  This is especially true in the case of an executable
  292.      * copied to a domain with wildcards.  The only safe action is not to
  293.      * define NO_WILDCARD_MX.  To this end, the #define has been removed
  294.      * from conf.h.  -pbp
  295.      */
  296.  
  297. # ifndef NO_WILDCARD_MX
  298.     _res.options &= ( ~RES_DEFNAMES & 0xffff ) ;
  299. # endif /* NO_WILDCARD_MX */
  300.     n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer));
  301. # ifndef NO_WILDCARD_MX
  302.     _res.options |= RES_DEFNAMES ;
  303. # endif /* NO_WILDCARD_MX */
  304.     if (n < 0)
  305.     {
  306.         if (tTd(8, 1))
  307.             printf("getcanonname:  res_search failed (errno=%d, h_errno=%d)\n",
  308.                 errno, h_errno);
  309.         return FALSE;
  310.     }
  311.  
  312.     /* find first satisfactory answer */
  313.     hp = (HEADER *)&answer;
  314.     ancount = ntohs(hp->ancount);
  315.  
  316.     /* we don't care about errors here, only if we got an answer */
  317.     if (ancount == 0)
  318.     {
  319.         if (tTd(8, 1))
  320.             printf("hp->rcode = %d, ancount=%d\n",
  321.                 hp->rcode, ancount);
  322.         return FALSE;
  323.     }
  324.     cp = (u_char *)&answer + sizeof(HEADER);
  325.     eom = (u_char *)&answer + n;
  326.     for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  327.         if ((n = dn_skipname(cp, eom)) < 0)
  328.             return FALSE;
  329.  
  330.     /*
  331.      * just in case someone puts a CNAME record after another record,
  332.      * check all records for CNAME; otherwise, just take the first
  333.      * name found.
  334.      */
  335.     for (first = 1; --ancount >= 0 && cp < eom; )
  336.     {
  337.         if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  338.             sizeof(nbuf))) < 0)
  339.             break;
  340.         if (first)
  341.         {            /* XXX */
  342.             (void)strncpy(host, nbuf, hbsize);
  343.             host[hbsize - 1] = '\0';
  344.             first = 0;
  345.         }
  346.         cp += n;
  347.         GETSHORT(type, cp);
  348.          cp += sizeof(u_short) + sizeof(u_long);
  349.         GETSHORT(n, cp);
  350.         if (type == T_CNAME)
  351.         {
  352.             /*
  353.              * assume that only one cname will be found.  More
  354.              * than one is undefined.  Copy so that if dn_expand
  355.              * fails, `host' is still okay.
  356.              */
  357.             if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  358.                 sizeof(nbuf))) < 0)
  359.                 break;
  360.             /* cp += n;  un-used  -pbp */
  361.             (void)strncpy(host, nbuf, hbsize); /* XXX */
  362.             host[hbsize - 1] = '\0';
  363.             if (++loopcnt > 8)    /* never be more than 1 */
  364.                 return FALSE;
  365.             goto loop;
  366.         }
  367.         else if (type == T_MX)
  368.         {
  369.             /*
  370.              * Be sure that the best MX record doesn't point
  371.              * to the local machine.  If it does, some other
  372.              * delivery method is assumed.
  373.              */
  374.  
  375.             u_short preference;
  376.  
  377.             GETSHORT(preference, cp);
  378.             if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
  379.                 sizeof(nbuf))) < 0)
  380.                 break;
  381.             cp += n;
  382.             if (tTd(8, 1))
  383.                 printf("getcanonname: MX host %s, preference %d\n",
  384.                     nbuf, preference);
  385.             if (preference < MailPreference)
  386.             {
  387.                 MailPreference = preference;
  388.                 (void) strcpy(MailAgent, nbuf);
  389.     }
  390.         }
  391.         else
  392.             cp += n;
  393.     }
  394.     if (MailAgent[0] == '\0')
  395.         return (FALSE);
  396.  
  397.     /* test MailAgent against $j */
  398.     if (MyHostName != NULL && strcasecmp(MailAgent, MyHostName) == 0)
  399.         return (FALSE);
  400.  
  401.     /* test MailAgent against $=j */
  402.     if (HostInClass(MailAgent, 'j') || HostInClass(MailAgent, 'w'))
  403.         return (FALSE);
  404.  
  405.     /* test MailAgent against our DNS name and aliases */
  406.     if ((MyAliases = myhostname(MyName, MAXNAME)) != NULL)
  407.     {
  408.         if (strcasecmp(MailAgent, MyName) == 0)
  409.             return FALSE;
  410.         for (; *MyAliases != NULL; MyAliases++)
  411.             if (strcasecmp(MailAgent, *MyAliases) == 0)
  412.                 return FALSE;
  413.         return TRUE;
  414.     }
  415.     else
  416.         return TRUE;
  417. }
  418.  
  419. #else /* !NAMED_BIND */
  420. /*
  421. **  GETCANONNAME -- Get the canonical name of the given host.
  422. **
  423. **    Use the gethostbyname() call to obtain the canonical name of
  424. **    the given host.  No check is made for MX records.
  425. **
  426. **    Parameters:
  427. **        host -- the name to canonicalize
  428. **        hbsize -- size of host string
  429. **
  430. **    Returns:
  431. **        TRUE -- Canonical name found
  432. **        FALSE -- Name not found or length > hbsize
  433. **
  434. **    Side Effects:
  435. **        The host argument is re-written with the canonical name.
  436. */
  437.  
  438. # include <netdb.h>
  439.  
  440. bool
  441. getcanonname(host, hbsize)
  442.     char *host;
  443.     int hbsize;
  444. {
  445.     struct hostent *hp;
  446.  
  447.     hp = gethostbyname(host);
  448.     if (hp == NULL)
  449.         return FALSE;
  450.  
  451.     if (strlen(hp->h_name) >= hbsize)
  452.         return FALSE;
  453.  
  454.     (void) strcpy(host, hp->h_name);
  455.     return TRUE;
  456. }
  457. #endif /* !NAMED_BIND */
  458.